package org.easy.db.generator;

import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.apache.velocity.app.VelocityEngine;
import org.easy.exception.GeneratorException;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Comparator;
import java.util.Map;
import java.util.Properties;

/**
 * @Description: 生成代码的模板引擎
 * @Author: wxl
 * @CreateTime: 2023/1/28 13:53
 */
@Slf4j
public class VelocityTemplateEngine {

    private final String outPutPath;

    private final VelocityContext context;

    private VelocityEngine velocityEngine;

    private final Map<String,String> templateMap;

    public VelocityTemplateEngine (GlobalConfigBuilder builder) {
        this.outPutPath = builder.getOutPutDir();
        this.templateMap = builder.getTemplateMap();
        Map<String,Object> objectMap = JSON.parseObject(JSON.toJSONString(builder));
        this.context = new VelocityContext(objectMap);
    }

    public VelocityTemplateEngine init () {
        if (null == velocityEngine) {
            Properties p = new Properties();
            p.setProperty("resource.loader.file.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
            p.setProperty(Velocity.FILE_RESOURCE_LOADER_PATH, "");
            p.setProperty(Velocity.ENCODING_DEFAULT, StandardCharsets.UTF_8.name());
            p.setProperty(Velocity.INPUT_ENCODING, StandardCharsets.UTF_8.name());
            p.setProperty("resource.loader.file.unicode", "true");
            velocityEngine = new VelocityEngine(p);
        }
        return this;
    }

    public void generator () {

        String outPutPath = this.getOutPath();
        boolean isError = false;
        StringBuilder errorStr = new StringBuilder();
        for (Map.Entry<String, String> entry : this.templateMap.entrySet()) {
            String template = entry.getKey();
            String filePath = outPutPath + entry.getValue();
            createDirIsNotExit(filePath);
            try {
                write(filePath,template);
            } catch (Exception e) {
                log.error("", e);
                isError = true;
                errorStr.append(e.getMessage());
                break;
            }
        }
        // 如果循环中有一个出现了异常
        if (isError) {
            deleteDir();
            throw new GeneratorException(errorStr.toString());
        }

    }

    public String getOutPath () {
        return this.outPutPath;
    }

    private void createDirIsNotExit (String filePath) {
        String fileName = filePath.substring(filePath.lastIndexOf(File.separator) + 1);
        String fileDir = filePath.replace(fileName, "");
        File directory = new File(fileDir);
        if (!directory.exists()) {
            boolean flag = directory.mkdirs();
            if (flag) {
                log.info("创建文件目录成功.......");
            }
        }
    }

    /**
     * 生成文件
     * @param filePath 生成文件的路径
     * @param templatePath 模板路径
     * @throws Exception 异常
     */
    private void write(String filePath,String templatePath) throws Exception{
        File writeFile = new File(filePath);
        Template template = velocityEngine.getTemplate(templatePath,StandardCharsets.UTF_8.name());
        try (FileOutputStream fos = new FileOutputStream(writeFile);
             OutputStreamWriter ow = new OutputStreamWriter(fos,StandardCharsets.UTF_8.name());
             BufferedWriter writer = new BufferedWriter(ow)) {
            template.merge(this.context, writer);
        }
    }

    /**
     * 删除文件夹及下面的所有文件
     */
    private void deleteDir(){
        File file = new File(getOutPath());
        if (file.exists()) {
            try {
                Files.walk(file.toPath())
                        .sorted(Comparator.reverseOrder())
                        .map(Path::toFile)
                        .forEach(File::delete);
            } catch (IOException e) {
                log.error("删除文件出现异常:{}",e.getMessage());
            }
        }
    }

}
